from abc import ABC, abstractmethod
from functools import lru_cache
from typing import List, Tuple, Optional

import pandas as pd


class Indicator(ABC):
    """
    一个纯粹的、可复用的计算单元。

    它接收一个Pandas Series作为输入，经过计算后，返回一个Pandas Series作为输出。
    它本身是无状态的，并且与DataFrame的结构或多周期数据完全解耦。
    """

    def __init__(self, source_column: Optional[Tuple[str, str]], **params):
        """
        Args:
            source_column (Optional[Tuple[str, str]]):
                一个元组代表数据源, e.g., ('1h', 'close')。
                对于像表达式这样需要多列的指标，可以为None。
            **params: 指标计算所需的参数 (e.g., period=20)。
        """
        self.source_column = source_column
        self.params = params
        # 将参数转换为可哈希的元组，用于缓存和唯一标识
        self._params_tuple = tuple(sorted(self.params.items()))
        self.column_name: Tuple[str, str] = self._generate_column_name()

    def _generate_column_name(self) -> Tuple[str, str]:
        """根据数据源和计算逻辑生成唯一的输出列名元组。"""
        # 默认实现，子类可以重写

        if self.params.get('name') is not None:
            return self.source_column[0], self.params.get('name')
        return self.source_column[0], self.__class__.__name__

    @lru_cache(maxsize=None)
    def _get_logic_name(self) -> str:
        """根据类名和参数生成计算逻辑的唯一标识符。"""
        if not self.params:
            return self.__class__.__name__
        params_str = "_".join(f"{v}" for k, v in self.params.items())
        return f"{self.__class__.__name__}_{params_str}"

    @property
    @lru_cache(maxsize=None)  # 使用缓存，因为名称对于相同参数的实例是固定的
    def name(self) -> str:
        """
        根据类名和参数生成一个描述性的、唯一的标识符。
        例如: "SmaIndicator(period=20)"
        """
        # 如果没有参数，只返回类名
        if self.params.get('name') is not None:
            return self.params['name']
        if not self.params:
            return self.__class__.__name__

        params_str = ", ".join(f"{k}={v}" for k, v in self.params.items())
        return f"{self.__class__.__name__}({params_str})"

    @abstractmethod
    def compute(self, df: pd.DataFrame) -> pd.Series:
        """
        核心计算逻辑。
        :param df: 完整的数据DataFrame。
        """
        raise NotImplementedError

    # --- 使得Indicator对象可哈希，以便在集合或字典键中使用 ---
    def __hash__(self):
        return hash((self.__class__, self._params_tuple))

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self.__hash__() == other.__hash__()

    def __repr__(self):
        return self.name


class RequiresIndicators(ABC):
    """
    一个混入类 (Mixin)，任何需要指标的组件都可以继承它，
    以提供一个标准化的方式来声明和获取指标依赖。
    """

    @abstractmethod
    def get_required_indicators(self) -> List[Indicator]:
        """
        子类应该重写此方法来返回它们需要的IndicatorRequest列表。
        """
        raise NotImplementedError
